package com.ktjiaoyu.crm.config.shiro;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.ktjiaoyu.crm.pojo.Right;
import com.ktjiaoyu.crm.service.RightService;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.shiro.mgt.SecurityManager;

import javax.annotation.Resource;

@Configuration
public class ShiroConfig {
    @Resource
    RightService rightService;

    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private int port;

    /**
     * 开启Shiro注解(如@RequiresRoles,@RequiresPermissions),
     * 需借助Spring AOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
     * 配置以下两个bean(DefaultAdvisorAutoProxyCreator和
     * thorizationAttributeSourceAdvisor)
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator =
                new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    /**
     * 开启Spring AOP对shiro注解支持
     *
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor
    authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor =
                new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Bean
    public MyShiroRealm myShiroRealm() {
        MyShiroRealm myShiroRealm=new MyShiroRealm();
        //开启缓存
        myShiroRealm.setCachingEnabled(true);
        //开启授权缓存
        myShiroRealm.setAuthorizationCachingEnabled(true);
        //缓存名称生成策略
        myShiroRealm.setAuthorizationCacheName("authrizationCache");
        //设置密码匹配器
        myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());

        return myShiroRealm;
    }

    @Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }

    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager() {
        DefaultWebSecurityManager defaultWebSecurityManager =
                new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(myShiroRealm());
        //注入记住我的管理者
        defaultWebSecurityManager.setRememberMeManager(cookieRememberMeManager());
        //注入session管理者
        defaultWebSecurityManager.setSessionManager(defaultWebSessionManager());
        //注入缓存管理者
        defaultWebSecurityManager.setCacheManager(redisCacheManager());

        return defaultWebSecurityManager;
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean() {
        ShiroFilterFactoryBean shiroFilterFactoryBean =
                new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager());

        //配置我们自己的登录页面
        shiroFilterFactoryBean.setLoginUrl("/login");
        //配置登录成功页面
        shiroFilterFactoryBean.setSuccessUrl("/main");
        //配置权限不足显示的页面
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");

        //请求路劲拦截
        Map<String, String> filter = new LinkedHashMap<>();
        //这些资源不需要保护；不管有没有登录直接放行
        //静态资源
        filter.put("/css/**", "anon");
        filter.put("/fonts/**", "anon");
        filter.put("/images/**", "anon");
        filter.put("/js/**", "anon");
        filter.put("/localcss/**", "anon");
        filter.put("/localjs/**", "anon");
        //登录请求
        filter.put("/dologin", "anon");
        //退出请求
        filter.put("/logout", "logout");

        //这些资源需要保护；不仅要登录，而且还要拥有指定的权限才能访问
//        filter.put("/user/list", "perms[用户列表]");
//        filter.put("/user/add", "perms[用户添加]");
//        filter.put("/user/save", "perms[用户保存]");
////        filter.put("/user/edit","perms[用户编辑]");
//        filter.put("/user/update", "perms[用户修改]");
//        filter.put("/user/delete", "perms[用户删除]");

        List<Right> list = rightService.findAllRights();
        for (Right right : list) {
            if(right.getRightUrl()!=null
                    && !right.getRightUrl().trim().equals("")){
                filter.put(right.getRightUrl(), "perms["+right.getRightCode()+"]");
            }
        }

        //除了上面配置的要保护资源，剩余的只要登录即可访问 放在最后
        filter.put("/**", "authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filter);

        return shiroFilterFactoryBean;
    }

    @Bean
    public SimpleCookie simpleCookie() {
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        simpleCookie.setMaxAge(24 * 60 * 60);
        return simpleCookie;
    }

    @Bean
    public CookieRememberMeManager cookieRememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager =
                new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(simpleCookie());
        cookieRememberMeManager.setCipherKey(
                Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));
        return cookieRememberMeManager;
    }

    /**
     * redis管理对象
     * @return
     */
    @Bean
    public RedisManager redisManager(){
        RedisManager redisManager=new RedisManager();
        redisManager.setHost(host);
        redisManager.setPort(port);

        return redisManager;
    }

    @Bean
    public RedisSessionDAO redisSessionDAO(){
        RedisSessionDAO redisSessionDAO=new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }

    @Bean
    public DefaultWebSessionManager defaultWebSessionManager(){
        DefaultWebSessionManager defaultWebSessionManager=
                new DefaultWebSessionManager();
        defaultWebSessionManager.setSessionDAO(redisSessionDAO());

        return defaultWebSessionManager;
    }

    @Bean
    public RedisCacheManager redisCacheManager(){
        RedisCacheManager redisCacheManager
                =new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        redisCacheManager.setExpire(30*60);
        redisCacheManager.setPrincipalIdFieldName("usrName");
        return redisCacheManager;
    }

    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher=
                new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        hashedCredentialsMatcher.setHashIterations(2);
        return hashedCredentialsMatcher;
    }
}
